<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.10">
<title>Build great native CLI apps in Java with GraalVM and Picocli</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment @import statement to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
:not(pre)>code.nobreak{word-wrap:normal}
:not(pre)>code.nowrap{white-space:nowrap}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details>summary:first-of-type{cursor:pointer;display:list-item;outline:none;margin-bottom:.75em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class="highlight"],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos{border-right:1px solid currentColor;opacity:.35;padding-right:.5em}
pre.pygments .lineno{border-right:1px solid currentColor;opacity:.35;display:inline-block;margin-right:.75em}
pre.pygments .lineno::before{content:"";margin-right:-.125em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock{max-width:100%;border-collapse:separate}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
td.tableblock>.content>:last-child.sidebarblock{margin-bottom:0}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd),table.stripes-even tr:nth-of-type(even),table.stripes-hover tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
.hidden {
    display: none;
}

.switch {
    border-width: 1px 1px 0 1px;
    border-style: solid;
    border-color: #7a2518;
    display: inline-block;
}

.switch--item {
    padding: 10px;
    background-color: #ffffff;
    color: #7a2518;
    display: inline-block;
    cursor: pointer;
}

.switch--item.selected {
    background-color: #7a2519;
    color: #ffffff;
}

</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
<script type="text/javascript">
function addBlockSwitches() {
    $('.primary').each(function() {
        primary = $(this);
        createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected");
        primary.children('.title').remove();
    });
    $('.secondary').each(function(idx, node) {
        secondary = $(node);
        primary = findPrimary(secondary);
        switchItem = createSwitchItem(secondary, primary.children('.switch'));
        switchItem.content.addClass('hidden');
        findPrimary(secondary).append(switchItem.content);
        secondary.remove();
    });
}

function createBlockSwitch(primary) {
    blockSwitch = $('<div class="switch"></div>');
    primary.prepend(blockSwitch);
    return blockSwitch;
}

function findPrimary(secondary) {
    candidate = secondary.prev();
    while (!candidate.is('.primary')) {
        candidate = candidate.prev();
    }
    return candidate;
}

function createSwitchItem(block, blockSwitch) {
    blockName = block.children('.title').text();
    content = block.children('.content').first().append(block.next('.colist'));
    item = $('<div class="switch--item">' + blockName + '</div>');
    item.on('click', '', content, function(e) {
        $(this).addClass('selected');
        $(this).siblings().removeClass('selected');
        e.data.siblings('.content').addClass('hidden');
        e.data.removeClass('hidden');
    });
    blockSwitch.append(item);
    return {'item': item, 'content': content};
}

$(addBlockSwitches);

</script>

</head>
<body class="article">
<div id="header">
<h1>Build great native CLI apps in Java with GraalVM and Picocli</h1>
<div class="details">
<span id="revnumber">version 4.5.2</span>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p><em>Let&#8217;s Put Java Back on the CLI Map</em></p>
</div>
<div class="paragraph">
<p>Takeaways:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Developers want to <strong>distribute</strong> their command line applications as a <strong>single native executable</strong>.</p>
</li>
<li>
<p><strong>GraalVM</strong> can compile your Java applications to single native images, but it has some limitations.</p>
</li>
<li>
<p><strong>Picocli</strong> is a modern library for writing CLI apps on the JVM which can help tackle GraalVM&#8217;s limitations including on Windows.</p>
</li>
<li>
<p>Setting up the GraalVM toolchain for creating native images on Windows is not well documented.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="images/fight-for-cli-apps.png" alt="fight for cli apps">
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_the_dream_java_executables">The Dream: Java Executables</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <a href="https://golang.org/">Go</a> programming language has become popular for writing command line applications.
There may be many reasons for this, but one aspect where Go shines is the ability to compile a program to a single native executable file.
This makes the program much easier to distribute.</p>
</div>
<div class="paragraph">
<p>Java programs have traditionally been hard to distribute because they require a Java Virtual Machine to be installed on the target machine.
It is possible to bundle a recent JVM with the application but that adds roughly 200MB to the package size.
Things are moving in the right direction: the Java Module System (JPMS), introduced in Java 9, includes the <a href="https://docs.oracle.com/javase/9/tools/jlink.htm#JSWOR-GUID-CECAC52B-CFEE-46CB-8166-F17A8E9280E9">jlink</a> utility that allows an application to create a custom, minimized, JRE, which can be as small as 30-40MB, and Java 14 will include the <a href="https://openjdk.java.net/jeps/343">jpackage</a> utility, which can create an installer that includes this minimum JRE with your application.</p>
</div>
<div class="paragraph">
<p>Still, for command line applications an installer is not ideal.
Ideally, we <a href="https://dev.to/uilicious/why-we-migrated-our-cli-from-nodejs-to-golang-1ol8">want to distribute</a> our CLI utility as a "real" native executable without a packaged runtime.
GraalVM allows us to do this with programs written in Java.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_graalvm">GraalVM</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://www.graalvm.org/">GraalVM</a> is a universal virtual machine that can run applications written in JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala, Clojure, Kotlin, and LLVM-based languages such as C and C++.
One interesting aspect is that GraalVM allows you to mix programming languages: programs partially written in JavaScript, R, Python, or Ruby can be called from Java and can share data with each other.
Another feature is the ability to create a native image, and this is what we will explore in this article.</p>
</div>
<div class="sect2">
<h3 id="_graalvm_native_images">GraalVM Native Images</h3>
<div class="paragraph">
<p><a href="https://www.graalvm.org/docs/reference-manual/native-image/">GraalVM Native Image</a> allows you to ahead-of-time compile Java code to a standalone executable, called a native image.
This executable includes the application, the libraries, the JDK and does not run on the Java VM, but includes necessary components like memory management and thread scheduling from a different virtual machine, called “Substrate VM”.
Substrate VM is the name for the runtime components (like the deoptimizer, garbage collector, thread scheduling etc.). The resulting program has faster startup time and lower runtime memory overhead compared to a Java VM.</p>
</div>
</div>
<div class="sect2">
<h3 id="_native_image_limitations">Native Image Limitations</h3>
<div class="paragraph">
<p>To keep the implementation small and concise, and also to allow aggressive ahead-of-time optimizations, Native Image does not support all features of Java.
The full set of <a href="https://github.com/oracle/graal/blob/master/substratevm/Limitations.md">limitations</a> is documented on the GitHub project.</p>
</div>
<div class="paragraph">
<p>Two limitations are of particular interest:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/oracle/graal/blob/master/substratevm/Limitations.md#reflection">reflection</a></p>
</li>
<li>
<p><a href="https://github.com/oracle/graal/blob/master/substratevm/Resources.md">resources</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Basically, to create a self-contained binary, the native image compiler needs to know up-front all the classes of your application, their dependencies, and the resources they use. Reflection and resource bundles often require configuration. We will see an example of this later on.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_picocli">Picocli</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://github.com/remkop/picocli">Picocli</a> is a modern library and framework for building command line applications on the JVM.
It supports Java, Groovy, Kotlin and Scala.
It is less than 3 years old but has become quite popular with over 500,000 downloads per month.
The Groovy language uses picocli to implement its <code>CliBuilder</code> DSL.</p>
</div>
<div class="paragraph">
<p>Picocli aims to be “the easiest way to create rich command line applications that can run on and off the JVM”.
It offers colored output, TAB autocompletion, subcommands, and some unique features compared to other JVM CLI libraries such as negatable options, repeating composite argument groups, repeating subcommands and sophisticated handling of quoted arguments.
Its source code is in a single file so it can optionally be included as source to avoid adding a dependency.
Picocli prides itself on its extensive and meticulous <a href="https://picocli.info/">documentation</a>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/picocli.Demo.png" alt="picocli.Demo">
</div>
</div>
<div class="paragraph">
<p>Picocli uses reflection, so it is vulnerable to GraalVM&#8217;s Java native image limitations, but it offers an annotation processor that generates the configuration files that address this limitation at compile time.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_a_concrete_use_case">A Concrete Use Case</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Let’s take a concrete example of a command line utility that we will write in Java and compile to a single native executable.
Along the way we will look at some features of the picocli library that help make our utility easy to use.</p>
</div>
<div class="paragraph">
<p>We will build a <code>checksum</code> CLI utility, that takes a named option <code>-a</code> or <code>--algorithm</code>, and a positional parameter, which is the file whose checksum to compute.</p>
</div>
<div class="paragraph">
<p>We want our users to be able to use our Java <code>checksum</code> utility just like they use applications written in C++ or other languages. Something like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>$ echo hi &gt; hi.txt

$ checksum -a md5 hi.txt
764efa883dda1e11db47671c4a3bbd9e

$ checksum -a sha1 hi.txt
55ca6286e3e4f4fba5d0448333fa99fc5a404a73</pre>
</div>
</div>
<div class="paragraph">
<p>This is the minimum we expect from a command line application, but we are not going to be satisfied with a lowest common denominator app, we want to create a great CLI application that delights our users. What does that mean and how do we do it?</p>
</div>
<div class="sect2">
<h3 id="_great_cli_apps_are_helpful">Great CLI Apps are Helpful</h3>
<div class="paragraph">
<p>We made a trade-off: by choosing a command line interface (CLI) instead of a graphical user interface (GUI), our application is less easy to learn to use for new users. We can partially make up for that by providing good online help.</p>
</div>
<div class="paragraph">
<p>Our application should show a usage help message when the user requests help with the <code>-h</code> or <code>--help</code> option, or when invalid user input is specified. It should also show version information when requested with <code>-V</code> or <code>--version</code>. We will see how picocli makes it easy to do this.</p>
</div>
<div class="sect3">
<h4 id="_user_experience">User Experience</h4>
<div class="paragraph">
<p>We can make our application more user-friendly by using colors on supported platforms. This doesn’t just look good, it also reduces the cognitive load on the user: the contrast makes the important information like commands, options, and parameters stand out from the surrounding text.</p>
</div>
<div class="paragraph">
<p>The usage help message generated by a picocli-based application uses colors by default.
Our <code>checksum</code> example looks something like this:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/checksum-usage-help.png" alt="checksum usage help">
</div>
</div>
<div class="paragraph">
<p>In general, applications should only output colors when they are used interactively; when executing a script we don’t want the log file cluttered with ANSI escape codes. Fortunately, picocli takes care of this automatically. This brings us to the next topic: good CLI apps are designed to be combined with other commands.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_great_cli_apps_work_well_with_others">Great CLI Apps Work Well with Others</h3>
<div class="sect3">
<h4 id="_stdout_vs_stderr">Stdout vs stderr</h4>
<div class="paragraph">
<p>Many CLI utilities use the standard I/O streams so they can be combined with other utilities. The devil is often in the details. When the user <em>requested</em> help, the application should print the usage help message to standard output. This allows users to pipe the output to another tool like <code>grep</code> or <code>less</code>.</p>
</div>
<div class="paragraph">
<p>On the other hand, on invalid input, the error message and usage help message should be printed to the standard error stream: in case the output of our program is used as input for another program, we don’t want our error message to disrupt things.</p>
</div>
</div>
<div class="sect3">
<h4 id="_exit_code">Exit Code</h4>
<div class="paragraph">
<p>When your program ends, it returns an exit status code. An exit code of zero is often used to indicate success, and a non-zero exit code often indicates a failure of some kind.</p>
</div>
<div class="paragraph">
<p>This allows users to chain together a number of commands using <code>&amp;&amp;</code>, knowing that if any command in the sequence fails, the whole sequence will stop.</p>
</div>
<div class="paragraph">
<p>By default, picocli returns <code>2</code> for invalid user input, <code>1</code> when an exception occurred in the business logic of the application, and zero otherwise (when everything went well).
Of course it is easy to configure other exit codes in your application, but for our <code>checksum</code> example the default values are fine.</p>
</div>
<div class="paragraph">
<p>Note that the picocli library will not call <code>System.exit</code>; it just returns an integer and it is up to the application to call <code>System.exit</code> or not.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_compact_code">Compact Code</h3>
<div class="paragraph">
<p>The above sections describe quite a bit of functionality.
You would think that this would require a lot of code to accomplish, but most of the "standard CLI behavior" is provided by the picocli library.
In our application, all we need to do is define our options and positional parameters, and implement the business logic by making our class <code>Callable</code> or <code>Runnable</code>.
We can bootstrap the application in our <code>main</code> method in one line of code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight nowrap"><code data-lang="java"><table class="CodeRay"><tr>
  <td class="line-numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td>
  <td class="code"><pre><span class="keyword">import</span> <span class="include">picocli.CommandLine</span>;
<span class="keyword">import</span> <span class="include">picocli.CommandLine.Command</span>;
<span class="keyword">import</span> <span class="include">picocli.CommandLine.Option</span>;
<span class="keyword">import</span> <span class="include">picocli.CommandLine.Parameters</span>;

<span class="keyword">import</span> <span class="include">java.io.File</span>;
<span class="keyword">import</span> <span class="include">java.math.BigInteger</span>;
<span class="keyword">import</span> <span class="include">java.nio.file.Files</span>;
<span class="keyword">import</span> <span class="include">java.security.MessageDigest</span>;
<span class="keyword">import</span> <span class="include">java.util.concurrent.Callable</span>;

<span class="annotation">@Command</span>(name = <span class="string"><span class="delimiter">&quot;</span><span class="content">checksum</span><span class="delimiter">&quot;</span></span>, mixinStandardHelpOptions = <span class="predefined-constant">true</span>,
      version = <span class="string"><span class="delimiter">&quot;</span><span class="content">checksum 4.0</span><span class="delimiter">&quot;</span></span>,
  description = <span class="string"><span class="delimiter">&quot;</span><span class="content">Prints the checksum (MD5 by default) of a file to STDOUT.</span><span class="delimiter">&quot;</span></span>)
<span class="type">class</span> <span class="class">CheckSum</span> <span class="directive">implements</span> <span class="predefined-type">Callable</span>&lt;<span class="predefined-type">Integer</span>&gt; {

  <span class="annotation">@Parameters</span>(index = <span class="string"><span class="delimiter">&quot;</span><span class="content">0</span><span class="delimiter">&quot;</span></span>, arity = <span class="string"><span class="delimiter">&quot;</span><span class="content">1</span><span class="delimiter">&quot;</span></span>,
        description = <span class="string"><span class="delimiter">&quot;</span><span class="content">The file whose checksum to calculate.</span><span class="delimiter">&quot;</span></span>)
  <span class="directive">private</span> <span class="predefined-type">File</span> file;

  <span class="annotation">@Option</span>(names = {<span class="string"><span class="delimiter">&quot;</span><span class="content">-a</span><span class="delimiter">&quot;</span></span>, <span class="string"><span class="delimiter">&quot;</span><span class="content">--algorithm</span><span class="delimiter">&quot;</span></span>},
    description = <span class="string"><span class="delimiter">&quot;</span><span class="content">MD5, SHA-1, SHA-256, ...</span><span class="delimiter">&quot;</span></span>)
  <span class="directive">private</span> <span class="predefined-type">String</span> algorithm = <span class="string"><span class="delimiter">&quot;</span><span class="content">MD5</span><span class="delimiter">&quot;</span></span>;

  <span class="comment">// this example implements Callable, so parsing, error handling</span>
  <span class="comment">// and handling user requests for usage help or version help</span>
  <span class="comment">// can be done with one line of code.</span>
  <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span>... args) {
    <span class="type">int</span> exitCode = <span class="keyword">new</span> CommandLine(<span class="keyword">new</span> CheckSum()).execute(args);
    <span class="predefined-type">System</span>.exit(exitCode);
  }

  <span class="annotation">@Override</span>
  <span class="directive">public</span> <span class="predefined-type">Integer</span> call() <span class="directive">throws</span> <span class="exception">Exception</span> { <span class="comment">// the business logic...</span>
    <span class="type">byte</span><span class="type">[]</span> data = Files.readAllBytes(file.toPath());
    <span class="type">byte</span><span class="type">[]</span> digest = <span class="predefined-type">MessageDigest</span>.getInstance(algorithm).digest(data);
    <span class="predefined-type">String</span> format = <span class="string"><span class="delimiter">&quot;</span><span class="content">%0</span><span class="delimiter">&quot;</span></span> + (digest.length*<span class="integer">2</span>) + <span class="string"><span class="delimiter">&quot;</span><span class="content">x%n</span><span class="delimiter">&quot;</span></span>;
    <span class="predefined-type">System</span>.out.printf(format, <span class="keyword">new</span> <span class="predefined-type">BigInteger</span>(<span class="integer">1</span>, digest));
    <span class="keyword">return</span> <span class="integer">0</span>;
  }
}</pre></td>
</tr></table></code></pre>
</div>
</div>
<div class="paragraph">
<p>We have an example of a realistic Java utility program.
Next, let’s take a look at turning it into a native executable.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_native_image">Native Image</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_reflection_configuration">Reflection Configuration</h3>
<div class="paragraph">
<p>We mentioned earlier that the native image compiler has some limitations: reflection is supported but <a href="https://github.com/oracle/graal/blob/master/substratevm/Configuration.md">requires configuration</a>.</p>
</div>
<div class="paragraph">
<p>This impacts picocli-based applications: at runtime, picocli uses reflection to discover any <code>@Command</code>-annotated subcommands, and the <code>@Option</code> and <code>@Parameters</code>-annotated command options and positional parameters.</p>
</div>
<div class="paragraph">
<p>Therefore, we need to provide GraalVM with a configuration file specifying all annotated classes, methods and fields. Such a configuration file looks something like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="json">[
  {
    <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">CheckSum</span><span class="delimiter">&quot;</span></span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allDeclaredConstructors</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allPublicConstructors</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allDeclaredMethods</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allPublicMethods</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">fields</span><span class="delimiter">&quot;</span></span> : [
      { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">algorithm</span><span class="delimiter">&quot;</span></span> },
      { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">file</span><span class="delimiter">&quot;</span></span> }
    ]
  },
  {
    <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">picocli.CommandLine$AutoHelpMixin</span><span class="delimiter">&quot;</span></span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allDeclaredConstructors</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allPublicConstructors</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allDeclaredMethods</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">allPublicMethods</span><span class="delimiter">&quot;</span></span> : <span class="value">true</span>,
    <span class="key"><span class="delimiter">&quot;</span><span class="content">fields</span><span class="delimiter">&quot;</span></span> : [
      { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">helpRequested</span><span class="delimiter">&quot;</span></span> },
      { <span class="key"><span class="delimiter">&quot;</span><span class="content">name</span><span class="delimiter">&quot;</span></span> : <span class="string"><span class="delimiter">&quot;</span><span class="content">versionRequested</span><span class="delimiter">&quot;</span></span> }
    ]
  }
]</code></pre>
</div>
</div>
<div class="paragraph">
<p>This quickly becomes quite cumbersome for utilities with many options, but fortunately we don’t need to do this by hand.</p>
</div>
</div>
<div class="sect2">
<h3 id="_picocli_annotation_processor">Picocli Annotation Processor</h3>
<div class="paragraph">
<p>The <code>picocli-codegen</code> module includes an annotation processor that can build a model from the picocli annotations at compile time rather than at runtime.</p>
</div>
<div class="paragraph">
<p>The annotation processor generates Graal configuration files under <code>META-INF/native-image/picocli-generated/$project</code> during compilation, to be included in the application jar.
This includes configuration files for <a href="https://github.com/oracle/graal/blob/master/substratevm/Reflection.md">reflection</a>, <a href="https://github.com/oracle/graal/blob/master/substratevm/Resources.md">resources</a> and <a href="https://github.com/oracle/graal/blob/master/substratevm/DynamicProxy.md">dynamic proxies</a>.
By embedding these configuration files, your jar is instantly Graal-enabled.
In most cases no further configuration is needed when generating a native image.</p>
</div>
<div class="paragraph">
<p>As a bonus, the annotation processor shows errors for invalid annotations or attributes immediately when you compile, instead of during testing at runtime, resulting in shorter feedback cycles.</p>
</div>
<div class="paragraph">
<p>So, all we need to do is compile our <code>CheckSum.java</code> source file with the <code>picocli-codegen</code> jar on the classpath:</p>
</div>
<div class="listingblock">
<div class="title">Compiling <code>CheckSum.java</code> and creating a <code>checksum.jar</code> on Linux. Replace the <code>:</code> path separator with <code>;</code> for these commands to work on Windows.</div>
<div class="content">
<pre>mkdir classes
javac -cp .:picocli-4.2.0.jar:picocli-codegen-4.2.0.jar -d classes CheckSum.java
cd classes &amp;&amp; jar -cvef CheckSum ../checksum.jar * &amp;&amp; cd ..</pre>
</div>
</div>
<div class="paragraph">
<p>You can see the generated configuration files are in the <code>META-INF/native-image/picocli-generated/</code> directory inside the jar:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>jar -tf checksum.jar

META-INF/
META-INF/MANIFEST.MF
CheckSum.class
META-INF/native-image/
META-INF/native-image/picocli-generated/
META-INF/native-image/picocli-generated/proxy-config.json
META-INF/native-image/picocli-generated/reflect-config.json
META-INF/native-image/picocli-generated/resource-config.json</pre>
</div>
</div>
<div class="paragraph">
<p>We are done with our application. Let&#8217;s make a native image as the next step!</p>
</div>
</div>
<div class="sect2">
<h3 id="_graalvm_native_image_toolchain">GraalVM Native Image Toolchain</h3>
<div class="paragraph">
<p>To create a native image, we need to install GraalVM, ensure the <code>native-image</code> utility is installed, and install the C/C++ compiler toolchain for the OS we are building on. I had some trouble doing this, so hopefully my notes below are useful to other developers.</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>Development is 10% inspiration and 90% getting your environment set up.</p>
</div>
</blockquote>
<div class="attribution">
&#8212; Unknown developer
</div>
</div>
<div class="sect3">
<h4 id="_install_graalvm">Install GraalVM</h4>
<div class="paragraph">
<p>First, install the latest version of GraalVM, 20.0 at the time of this writing.
The GraalVM <a href="https://www.graalvm.org/docs/getting-started/">Getting Started</a> page is the best place to get the most up-to-date instructions for installing GraalVM in various operating systems and containers.</p>
</div>
</div>
<div class="sect3">
<h4 id="_install_the_native_image_utility">Install the Native Image Utility</h4>
<div class="paragraph">
<p>GraalVM comes with a <code>native-image</code> generator utility.
In recent versions of GraalVM, this needs to be downloaded first and installed separately with the <a href="https://www.graalvm.org/docs/reference-manual/install-components/">Graal Updater</a> tool:</p>
</div>
<div class="listingblock">
<div class="title">Installing the <code>native-image</code> generator utility for Java 11 on Linux</div>
<div class="content">
<pre>gu install -L /path/to/native-image-installable-svm-java11-linux-amd64-20.0.0.jar</pre>
</div>
</div>
<div class="paragraph">
<p>This step also became necessary with the Windows version of GraalVM since 20.0.</p>
</div>
<div class="paragraph">
<p>For more details, see the <a href="https://www.graalvm.org/docs/reference-manual/native-image/">Native Image</a> section of the GraalVM <a href="https://www.graalvm.org/docs/reference-manual/">Reference Manual</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_install_compiler_toolchain">Install Compiler Toolchain</h4>
<div class="sect4">
<h5 id="_linux_and_macos_compiler_toolchain">Linux and MacOS Compiler Toolchain</h5>
<div class="paragraph">
<p>For compilation <code>native-image</code> depends on the local toolchain, so on Linux and MacOS we need <code>glibc-devel</code>, <code>zlib-devel</code> (header files for the C library and zlib) and <code>gcc</code> to be available on our system.</p>
</div>
<div class="paragraph">
<p>To accomplish this on Linux: <code>sudo dnf install gcc glibc-devel zlib-devel</code> or <code>sudo apt-get install build-essential libz-dev</code>.</p>
</div>
<div class="paragraph">
<p>On macOS, execute <code>xcode-select --install</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="_windows_compiler_toolchain_for_java_8">Windows Compiler Toolchain for Java 8</h5>
<div class="paragraph">
<p>GraalVM started to offer experimental support for Windows native images since release 19.2.0.</p>
</div>
<div class="paragraph">
<p>Windows support is still experimental, and the official documentation is sparse on details regarding native images on Windows. From version 19.3, GraalVM supports both Java 8 and Java 11, and on Windows these require different tool chains.</p>
</div>
<div class="paragraph">
<p>To build native images using the Java 8 version of GraalVM, you need the <a href="https://www.microsoft.com/en-us/download/details.aspx?id=8442">Microsoft Windows SDK for Windows 7 and .NET Framework 4</a> as well as the <a href="https://stackoverflow.com/a/45784634/873282">C compilers from KB2519277</a>.
You can install these using <a href="https://chocolatey.org/docs/installation">chocolatey</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>choco install windows-sdk-7.1 kb2519277</pre>
</div>
</div>
<div class="paragraph">
<p>Then (from the <code>cmd</code> prompt), activate the sdk-7.1 environment:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd"</pre>
</div>
</div>
<div class="paragraph">
<p>This starts a new Command Prompt, with the sdk-7.1 environment enabled.
Run all subsequent commands in this Command Prompt window.
This works for all Java 8 versions of GraalVM from 19.2.0 to 20.0.</p>
</div>
</div>
<div class="sect4">
<h5 id="_windows_compiler_toolchain_for_java_11">Windows Compiler Toolchain for Java 11</h5>
<div class="paragraph">
<p>To build native images using the Java 11 version of GraalVM (19.3.0 and greater),
you can either install the Visual Studio 2017 IDE (making sure to include Visual C tools for CMake),
or you can install the Visual C Build Tools Workload for Visual Studio 2017 Build Tools
using <a href="https://chocolatey.org/docs/installation">chocolatey</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>choco install visualstudio2017-workload-vctools</pre>
</div>
</div>
<div class="paragraph">
<p>After installation, set up the environment from the <code>cmd</code> prompt with this command:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat"</pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
If you installed the Visual Studio 2017 IDE, replace <code>BuildTools</code> in the above command with either <code>Community</code> or <code>Enterprise</code>, depending on your version of Visual Studio.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Then run <code>native-image</code> in that Command Prompt window.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_creating_a_native_image">Creating a Native Image</h3>
<div class="paragraph">
<p>The <code>native-image</code> utility can take a Java application and compile it to a native image that can run as a native executable on the platform that it is compiled on.
On Linux this can look like this:</p>
</div>
<div class="listingblock">
<div class="title">Creating a native image on Linux</div>
<div class="content">
<pre>$ /usr/lib/jvm/graalvm/bin/native-image \
    -cp classes:picocli-4.2.0.jar --no-server \
    --static -H:Name=checksum  CheckSum</pre>
</div>
</div>
<div class="paragraph">
<p>The <code>native-image</code> utility will take about a minute to complete on my laptop, and produces output like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>[checksum:1073]    classlist:   3,124.74 ms,  1.14 GB
[checksum:1073]        (cap):   2,885.31 ms,  1.14 GB
[checksum:1073]        setup:   4,767.19 ms,  1.14 GB
[checksum:1073]   (typeflow):   8,733.59 ms,  1.94 GB
[checksum:1073]    (objects):   6,073.44 ms,  1.94 GB
[checksum:1073]   (features):     313.28 ms,  1.94 GB
[checksum:1073]     analysis:  15,384.41 ms,  1.94 GB
[checksum:1073]     (clinit):     322.84 ms,  1.94 GB
[checksum:1073]     universe:     793.02 ms,  1.94 GB
[checksum:1073]      (parse):   2,191.69 ms,  1.94 GB
[checksum:1073]     (inline):   2,064.62 ms,  2.13 GB
[checksum:1073]    (compile):  14,960.43 ms,  2.73 GB
[checksum:1073]      compile:  20,040.78 ms,  2.73 GB
[checksum:1073]        image:   1,272.17 ms,  2.73 GB
[checksum:1073]        write:     722.20 ms,  2.73 GB
[checksum:1073]      [total]:  46,743.28 ms,  2.73 GB</pre>
</div>
</div>
<div class="paragraph">
<p>At the end, we have a native Linux executable.
Interestingly, the native binary created with the Java 11 version of GraalVM is a bit bigger than the one created with the Java 8 version of GraalVM:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="bash">-rwxrwxrwx 1 remko remko 14744296 Feb 19 09:51 java11-20.0/checksum*
-rwxrwxrwx 1 remko remko 12393600 Feb 19 09:48 java8-20.0/checksum*</code></pre>
</div>
</div>
<div class="paragraph">
<p>We can see the binary is 12.4 - 14.7 MB in size.
We can consider that big or small, depending on what we compare it with.
For me it is an acceptable size.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s run the application to verify that it works.
While we are at it we may as well compare the startup times of running the application on a normal JIT-based JVM to that of the native image:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>$ time java -cp classes:picocli-4.2.0.jar CheckSum hi.txt
764efa883dda1e11db47671c4a3bbd9e

real    0m0.415s   ← startup is 415 millis with normal Java
user    0m0.609s
sys     0m0.313s</pre>
</div>
</div>
<div class="listingblock">
<div class="content">
<pre>$ time ./checksum hi.txt
764efa883dda1e11db47671c4a3bbd9e

real    0m0.004s   ← native image starts up in 4 millis
user    0m0.002s
sys     0m0.002s</pre>
</div>
</div>
<div class="paragraph">
<p>So, on Linux at least, we can now distribute our Java application as a single native executable. What is the story on Windows?</p>
</div>
</div>
<div class="sect2">
<h3 id="_native_image_on_windows">Native Image on Windows</h3>
<div class="paragraph">
<p>Native image support on Windows has some gotchas, so we will look at this in more detail.</p>
</div>
<div class="sect3">
<h4 id="_creating_native_images_on_windows">Creating Native Images on Windows</h4>
<div class="paragraph">
<p>Creating the native image itself is not a problem. For example:</p>
</div>
<div class="listingblock">
<div class="title">Creating a native image on Windows</div>
<div class="content">
<pre>C:\apps\graalvm-ce-java8-20.0.0\bin\native-image ^
  -cp picocli-4.2.0.jar --static -jar checksum.jar</pre>
</div>
</div>
<div class="paragraph">
<p>We get similar output from the <code>native-image.cmd</code> utility on Windows as what we saw on Linux, taking a comparable amount of time, and resulting in a slightly smaller executable of 11.3 MB for the Java 8 version of GraalVM, and 14.2 MB for a binary created with the Java 11 version of GraalVM.</p>
</div>
<div class="paragraph">
<p>The binaries work fine, with one difference: we don&#8217;t see ANSI colors on the console.
Let&#8217;s look at fixing that.</p>
</div>
</div>
<div class="sect3">
<h4 id="_windows_native_images_with_colored_output">Windows Native Images with Colored Output</h4>
<div class="paragraph">
<p>To get ANSI colors in the Windows command prompt, we need to use the <a href="https://github.com/fusesource/jansi">Jansi library</a>.
Unfortunately, Jansi (as of version 1.18) has <a href="https://github.com/fusesource/jansi/issues/162">some problems</a> that mean it fails to produce colored output in a GraalVM native image.
To work around this, picocli offers a <a href="https://github.com/remkop/picocli-jansi-graalvm">Jansi companion library</a>, <code>picocli-jansi-graalvm</code>, that allows the Jansi library to work correctly in GraalVM native images on Windows.</p>
</div>
<div class="paragraph">
<p>We change the <code>main</code> method to tell Jansi to enable rendering ANSI escape codes on Windows, like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><table class="CodeRay"><tr>
  <td class="line-numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td>
  <td class="code"><pre><span class="comment">//...</span>
<span class="keyword">import</span> <span class="include">picocli.jansi.graalvm.AnsiConsole</span>;
<span class="comment">//...</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">CheckSum</span> <span class="directive">implements</span> <span class="predefined-type">Callable</span>&lt;<span class="predefined-type">Integer</span>&gt; {

  <span class="comment">// ...</span>

  <span class="directive">public</span> <span class="directive">static</span> <span class="type">void</span> main(<span class="predefined-type">String</span><span class="type">[]</span> args) {
    <span class="type">int</span> exitCode = <span class="integer">0</span>;
    <span class="comment">// enable colors on Windows</span>
    <span class="keyword">try</span> (AnsiConsole ansi = AnsiConsole.windowsInstall()) {
      exitCode = <span class="keyword">new</span> CommandLine(<span class="keyword">new</span> CheckSum()).execute(args);
    }
    <span class="predefined-type">System</span>.exit(exitCode);
  }
}</pre></td>
</tr></table></code></pre>
</div>
</div>
<div class="paragraph">
<p>And build a new native image with this command (note that from GraalVM 19.3, it became necessary to quote the jars on the classpath):</p>
</div>
<div class="listingblock">
<div class="content">
<pre>set GRAALVM_HOME=C:\apps\graalvm-ce-java11-20.0.0

%GRAALVM_HOME%\bin\native-image ^
  -cp "picocli-4.2.0.jar;jansi-1.18.jar;picocli-jansi-graalvm-1.1.0.jar;checksum.jar" ^
  picocli.nativecli.demo.CheckSum checksum</pre>
</div>
</div>
<div class="paragraph">
<p>And we have colors in our DOS console application:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/checksum-usage-help-dos-console.png" alt="checksum usage help dos console">
</div>
</div>
<div class="paragraph">
<p>It takes a little extra effort, but now our native Windows CLI app can use color contrast to provide a similar user experience as on Linux.</p>
</div>
<div class="paragraph">
<p>The size of the resulting binaries did not change much with the addition of the Jansi libraries: building with Java 11 GraalVM gave a 14.3 MB binary, building with Java 8 GraalVM gave a 11.3 MB binary.</p>
</div>
</div>
<div class="sect3">
<h4 id="_running_native_images_on_windows">Running Native Images on Windows</h4>
<div class="paragraph">
<p>We are almost done, but there is one more gotcha that is not immediately apparent.</p>
</div>
<div class="paragraph">
<p>The native binary we just created works fine on the machine where we just built it, but when you run it on a different Windows machine, you may see the following error:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/msvcr100.dll-not-found-dialog-en.png" alt="msvcr100.dll not found dialog en">
</div>
</div>
<div class="paragraph">
<p>It turns out that our native image <a href="https://github.com/oracle/graal/issues/1407">needs</a> the <code>msvcr100.dll</code> from VS C++ Redistributable 2010.
This dll can be placed in the same directory as the <code>exe</code>, or in <code>C:\Windows\System32</code>.
There is <a href="https://github.com/oracle/graal/issues/1762">work in progress</a> to try to improve on this.</p>
</div>
<div class="paragraph">
<p>With GraalVM for Java 11, we get a similar error, except that it reports a different missing DLL, the <code>VCRUNTIME140.dll</code>:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/system-error-vcruntime140.dll-is-missing-from-your-computer-en.png" alt="system error vcruntime140.dll is missing from your computer en">
</div>
</div>
<div class="paragraph">
<p>For now, we will have to distribute these DLLs with our application, or tell our users to download and install the <a href="https://www.microsoft.com/en-us/download/details.aspx?id=52685">Microsoft Visual C++ 2015 Redistributable Update 3 RC</a> to get the <code>VCRUNTIME140.dll</code> for Java 11-based native images, or <a href="https://www.microsoft.com/en-hk/download/details.aspx?id=13523">Microsoft Visual C++ 2010 SP1 Redistributable Package (x64)</a> to get the <code>msvcr100.dll</code> for Java 8-based native images.</p>
</div>
<div class="paragraph">
<p>GraalVM does not support cross-compilation, although it may in the future. For now, we need to compile on Linux to get a Linux executable, compile on MacOS to get a MacOS executable, and compile on Windows to get a Windows executable.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Command line applications are the canonical use case for GraalVM native images: we can now develop in Java (or another JVM language) and distribute our CLI applications as a <strong>single, relatively small, native executable</strong>. (Except on Windows, where we may need to distribute an additional runtime DLL.) The fast startup and reduced memory footprint are nice bonuses.</p>
</div>
<div class="paragraph">
<p>GraalVM native images have some limitations, and applications may need to do some work before they can be turned into a native image.</p>
</div>
<div class="paragraph">
<p><a href="https://github.com/remkop/picocli/">Picocli</a> makes it easy to write command line applications in many JVM-based languages, and provides several extras to painlessly turn your CLI applications into native images.</p>
</div>
<div class="paragraph">
<p>Give Picocli and GraalVM a try for your next command line application!</p>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 4.5.2<br>
Last updated 2020-09-12 12:34:25 +0900
</div>
</div>
<style>
/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */
pre.CodeRay{background:#f7f7f8}
.CodeRay .line-numbers{border-right:1px solid currentColor;opacity:.35;padding:0 .5em 0 0}
.CodeRay span.line-numbers{display:inline-block;margin-right:.75em}
.CodeRay .line-numbers strong{color:#000}
table.CodeRay{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.CodeRay td{vertical-align:top;line-height:inherit}
table.CodeRay td.line-numbers{text-align:right}
table.CodeRay td.code{padding:0 0 0 .75em}
.CodeRay .debug{color:#fff !important;background:#000080 !important}
.CodeRay .annotation{color:#007}
.CodeRay .attribute-name{color:#000080}
.CodeRay .attribute-value{color:#700}
.CodeRay .binary{color:#509}
.CodeRay .comment{color:#998;font-style:italic}
.CodeRay .char{color:#04d}
.CodeRay .char .content{color:#04d}
.CodeRay .char .delimiter{color:#039}
.CodeRay .class{color:#458;font-weight:bold}
.CodeRay .complex{color:#a08}
.CodeRay .constant,.CodeRay .predefined-constant{color:#008080}
.CodeRay .color{color:#099}
.CodeRay .class-variable{color:#369}
.CodeRay .decorator{color:#b0b}
.CodeRay .definition{color:#099}
.CodeRay .delimiter{color:#000}
.CodeRay .doc{color:#970}
.CodeRay .doctype{color:#34b}
.CodeRay .doc-string{color:#d42}
.CodeRay .escape{color:#666}
.CodeRay .entity{color:#800}
.CodeRay .error{color:#808}
.CodeRay .exception{color:inherit}
.CodeRay .filename{color:#099}
.CodeRay .function{color:#900;font-weight:bold}
.CodeRay .global-variable{color:#008080}
.CodeRay .hex{color:#058}
.CodeRay .integer,.CodeRay .float{color:#099}
.CodeRay .include{color:#555}
.CodeRay .inline{color:#000}
.CodeRay .inline .inline{background:#ccc}
.CodeRay .inline .inline .inline{background:#bbb}
.CodeRay .inline .inline-delimiter{color:#d14}
.CodeRay .inline-delimiter{color:#d14}
.CodeRay .important{color:#555;font-weight:bold}
.CodeRay .interpreted{color:#b2b}
.CodeRay .instance-variable{color:#008080}
.CodeRay .label{color:#970}
.CodeRay .local-variable{color:#963}
.CodeRay .octal{color:#40e}
.CodeRay .predefined{color:#369}
.CodeRay .preprocessor{color:#579}
.CodeRay .pseudo-class{color:#555}
.CodeRay .directive{font-weight:bold}
.CodeRay .type{font-weight:bold}
.CodeRay .predefined-type{color:inherit}
.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold}
.CodeRay .key{color:#808}
.CodeRay .key .delimiter{color:#606}
.CodeRay .key .char{color:#80f}
.CodeRay .value{color:#088}
.CodeRay .regexp .delimiter{color:#808}
.CodeRay .regexp .content{color:#808}
.CodeRay .regexp .modifier{color:#808}
.CodeRay .regexp .char{color:#d14}
.CodeRay .regexp .function{color:#404;font-weight:bold}
.CodeRay .string{color:#d20}
.CodeRay .string .string .string{background:#ffd0d0}
.CodeRay .string .content{color:#d14}
.CodeRay .string .char{color:#d14}
.CodeRay .string .delimiter{color:#d14}
.CodeRay .shell{color:#d14}
.CodeRay .shell .delimiter{color:#d14}
.CodeRay .symbol{color:#990073}
.CodeRay .symbol .content{color:#a60}
.CodeRay .symbol .delimiter{color:#630}
.CodeRay .tag{color:#008080}
.CodeRay .tag-special{color:#d70}
.CodeRay .variable{color:#036}
.CodeRay .insert{background:#afa}
.CodeRay .delete{background:#faa}
.CodeRay .change{color:#aaf;background:#007}
.CodeRay .head{color:#f8f;background:#505}
.CodeRay .insert .insert{color:#080}
.CodeRay .delete .delete{color:#800}
.CodeRay .change .change{color:#66f}
.CodeRay .head .head{color:#f4f}
</style>
</body>
</html>